`include "../codigo/Alu.v"

module test_alu();

    // Alu Inputs
    reg [31:0] t_a;
    reg [31:0] t_b;
    reg [2:0]  t_op;
    reg [0:0]  t_unsig;

    // Alu Outputs
    wire [0:0]  t_compout;
    wire [0:0]  t_overflow;
    wire [31:0] t_aluout;

    // Task to display results in a binary format
    task Display_Binary;
        begin
            #1 $display("Cycle:        %d", $time);
               $display("Alu Inputs:");
               $display("    a:        %b", t_a);
               $display("    b:        %b", t_b);
               $display("    op:       %b", t_op);
               $display("    unsig:    %b", t_unsig);
               $display("Alu Outputs:");
               $display("    aluout:   %b", t_aluout);
               $display("    compout:  %b", t_compout);
               $display("    overflow: %b", t_overflow);
               $display("##############################################");
        end
    endtask

    // Task to display results in a decimal format
    task Display_Decimal;
        begin
            #1 $display("Cycle:        %d", $time);
               $display("Alu Inputs:");
               $display("    a:        %d", t_a);
               $display("    b:        %d", t_b);
               $display("    op:       %b", t_op);
               $display("    unsig:    %b", t_unsig);
               $display("Alu Outputs:");
               $display("    aluout:   %d", t_aluout);
               $display("    compout:  %b", t_compout);
               $display("    overflow: %b", t_overflow);
               $display("##############################################");
        end
    endtask

    // Operation Tests
    task Operation_Tests;
        begin

            //Consider all inputs unsigned
            t_unsig <= #0 1'b1;
    
            // Test AND
            t_a  <= #0 32'h0000ffff;
            t_b  <= #0 32'h00ffff00; 
        	t_op <= #0 3'b000;
            $display("Test AND = 000");
            Display_Binary;
    
            // Test OR
            t_a  <= #0 32'h0000ffff;
            t_b  <= #0 32'h00ffff00; 
        	t_op <= #0 3'b001;
            $display("Test OR = 001");
            Display_Binary;
        
            // Test ADD
            t_a  <= #0 32'd25;
            t_b  <= #0 32'd12; 
        	t_op <= #0 3'b010;
            $display("Test ADD = 010");
            Display_Decimal;
        
            // Test Nothing
            t_a  <= #0 32'h0000ffff;
            t_b  <= #0 32'h00ffff00; 
        	t_op <= #0 3'b011;
            $display("Test Nothing = 010");
            Display_Binary;
        
            // Test NOR
            t_a  <= #0 32'h0000ffff;
            t_b  <= #0 32'h00ffff00; 
    	    t_op <= #0 3'b100;
            $display("Test NOR = 100");
            Display_Binary;


            // Test XOR
            t_a  <= #0 32'h0000ffff;
            t_b  <= #0 32'h00ffff00; 
        	t_op <= #0 3'b101;
            $display("Test XOR = 101");
            Display_Binary;

            // Test SUB
            t_a  <= #0 32'd25;
            t_b  <= #0 32'd12; 
        	t_op <= #0 3'b110;
            $display("Test SUB = 110");
            Display_Decimal;
        
            // Test Nothing
            t_a  <= #0 32'h0000ffff;
            t_b  <= #0 32'h00ffff00; 
        	t_op <= #0 3'b111;
            $display("Test Nothing = 111");
            Display_Binary;
        
        end
    endtask

    // Compout tests
    task Compout_Tests;
        begin

            //Consider all inputs unsigned
            t_unsig <= #0 1'b1;
            
            // Test Compout: Unsigned and a < b
            t_a  <= #0 32'h00000002; 
            t_b  <= #0 32'hfffffffe;
        	t_op <= #0 3'b010;
            $display("Test Compout: Unsigned and a < b");
            Display_Decimal;
        
            // Test Compout: Unsigned and a > b
            t_a  <= #0 32'hfffffffe;
            t_b  <= #0 32'h00000002; 
        	t_op <= #0 3'b010;
            $display("Test Compout: Unsigned and a > b");
            Display_Decimal;
        
            // Test Compout: Unsigned and a = b
            t_a  <= #0 32'h00000002;
            t_b  <= #0 32'h00000002; 
        	t_op <= #0 3'b010;
            $display("Test Compout: Unsigned and a = b");
            Display_Decimal;
        
            //Consider all inputs signed
            t_unsig <= #0 1'b0;
            
            // Test Compout: Signed, a > b, a positive and b negative
            t_a  <= #0 32'h00000002; 
            t_b  <= #0 -32'h00000002;
        	t_op <= #0 3'b010;
            $display("Test Compout: Signed, a > b, a positive and b negative");
            Display_Decimal;
        
            // Test Compout:  Signed, a < b, a negative and b positive
            t_a  <= #0 -32'h00000002;
            t_b  <= #0 32'h00000002; 
        	t_op <= #0 3'b010;
            $display("Test Compout: Signed, a < b, a negative and b positive");
            Display_Decimal;
        
            // Test Compout: Signed, a > b, both positive
            t_a  <= #0 32'h00000002; 
            t_b  <= #0 32'h00000001;
        	t_op <= #0 3'b010;
            $display("Test Compout: Signed, a > b, both positive");
            Display_Decimal;
        
            // Test Compout:  Signed, a < b, both positive
            t_a  <= #0 32'h00000001;
            t_b  <= #0 32'h00000002; 
        	t_op <= #0 3'b010;
            $display("Test Compout: Signed, a < b, both positive");
            Display_Decimal;
        
            // Test Compout: Signed, a > b, both negative
            t_a  <= #0 -32'h00000001; 
            t_b  <= #0 -32'h00000002;
        	t_op <= #0 3'b010;
            $display("Test Compout: Signed, a > b, both negative");
            Display_Decimal;
        
            // Test Compout:  Signed, a < b, both negative
            t_a  <= #0 -32'h00000002;
            t_b  <= #0 -32'h00000001; 
        	t_op <= #0 3'b010;
            $display("Test Compout: Signed, a < b, both negative");
            Display_Decimal;
        
            // Test Compout: Signed and a = b, both positive
            t_a  <= #0 32'h00000002;
            t_b  <= #0 32'h00000002; 
        	t_op <= #0 3'b010;
            $display("Test Compout: Signed and a = b, both positive");
            Display_Decimal;
            
            // Test Compout: Signed and a = b, both negative
            t_a  <= #0 -32'h00000002;
            t_b  <= #0 -32'h00000002; 
        	t_op <= #0 3'b010;
            $display("Test Compout: Signed and a = b, both negative");
            Display_Decimal;
        
        end
    endtask

    // Overflow tests
    task Overflow_Tests;
        begin
            
            //Consider all inputs signed
            t_unsig <= #0 1'b0;
            
            // Both positive
            t_a  <= #0 32'h7fffffff;
            t_b  <= #0 32'h00000002; 
        	t_op <= #0 3'b010;
            $display("Test Overflow: Both positive");
            Display_Decimal;
        
            // Both negative
            t_a  <= #0 -32'h7fffffff;
            t_b  <= #0 -32'h00000002; 
        	t_op <= #0 3'b010;
            $display("Test Overflow: both negative");
            Display_Decimal;
        
            // a positive and b neagtive
            t_a  <= #0 32'h00000002;
            t_b  <= #0 -32'h7fffffff; 
        	t_op <= #0 3'b110;
            $display("Test Overflow: a positive and b negative");
            Display_Decimal;
        
            // a negative and b positive
            t_a  <= #0 -32'h7fffffff;
            t_b  <= #0 32'h00000002; 
        	t_op <= #0 3'b110;
            $display("Test Overflow: a negative and b positive");
            Display_Decimal;
        
        end
    endtask

    // Alu Tests
    initial begin

        $display("##############################################");
        $display("Starting Alu Tests");
        $display("##############################################");
        $display("Operation Tests");
        $display("##############################################");
        Operation_Tests;
        $display("Compout Tests");
        $display("##############################################");
        Compout_Tests;
        $display("Overflow Tests");
        $display("##############################################");
        Overflow_Tests;
    end

    Alu t_alu(.a(t_a),
        .b(t_b),
        .op(t_op),
        .aluout(t_aluout),
        .unsig(t_unsig),
        .compout(t_compout),
        .overflow(t_overflow));

endmodule
